/*
 * TilemapLoader.cpp
 *
 *  Created on: 2009/02/04
 *      Author: Yongshik Cho
 */

#include "TilemapLoader.h"
#include "SoundReader.h"
#include "PathReader.h"
#include "CollisionReader.h"
#include "TileReader.h"
#include "ShapeReader.h"
#include "TextReader.h"
#include "ParticleReader.h"
#include "SpriteLoader.h"
#include "../ScriptManager.h"
#include "../SceneManager.h"

const std::string TilemapLoader::_TILEMAP_TAG 		= "Tilemap";
const std::string TilemapLoader::_SHAPE_TAG			= "Shape";


Tilemap* TilemapLoader::parse(const String& path)
{
#ifdef UNICODE
	char mbstr[512]; memset(mbstr, 0, 512);
	::WideCharToMultiByte(CP_UTF8, 0, path.c_str(), (int32)path.size(), mbstr, 512, 0, 0);
	TiXmlDocument* doc = new TiXmlDocument(mbstr);
#else
	TiXmlDocument* doc = new TiXmlDocument(path.c_str());
#endif
	if(!doc)
		AltoThrow(Exception::ERR_MEMORY);

	if(!doc->LoadFile(TIXML_ENCODING_UTF8))
		return 0;

	return parse(doc->FirstChildElement(_TILEMAP_TAG.c_str()));
}

Tilemap* TilemapLoader::parse(TiXmlElement* element)
{
	Tilemap* tilemap = new Tilemap();
	if(!tilemap)
		AltoThrow(Exception::ERR_MEMORY);

	char* sName = (char*)element->Attribute(TileReader::_NAME_TAG.c_str());
	TiXmlElement* node = element->FirstChildElement(TileReader::_NAME_TAG.c_str()); if(node) sName = (char*)node->GetText();

	if(sName)
#ifdef UNICODE
	{
		TCHAR wstr[512]; memset(wstr, 0, sizeof(wstr));
		::MultiByteToWideChar(CP_UTF8, 0, sName, (int32)strlen(sName), wstr, 512);
		tilemap->setName(wstr);
	}
#else
		tilemap->setName(sName);
#endif

	for(TiXmlElement* collision=element->FirstChildElement(TileReader::_COLLISION_TAG.c_str());
		collision;collision=collision->NextSiblingElement(TileReader::_COLLISION_TAG.c_str()))
	{
		Collidable* collidable = CollisionReader::parse(collision);
		if(collidable)
			tilemap->addCollidable(collidable);
	}

	for(TiXmlElement* path=element->FirstChildElement(SpriteLoader::_PATH_TAG.c_str());
		path;path=path->NextSiblingElement(SpriteLoader::_PATH_TAG.c_str()))
	{
		Path* altoPath = PathReader::parse(path);
		if(altoPath)
			tilemap->addPath(altoPath);
	}

	for(TiXmlElement* elem=element->FirstChildElement(SpriteLoader::_SOUND_TAG.c_str());
		elem;elem=elem->NextSiblingElement(SpriteLoader::_SOUND_TAG.c_str()))
	{
		Audible* audible = SoundReader::parse(elem);
		if(audible)
			tilemap->addAudible(audible);
	}

	/*
	 * 	<Tile path='PC_M000.png' xCount=4 yCount=9/>
	 */
	for(TiXmlElement* elem=element->FirstChildElement(SpriteLoader::_TILE_TAG.c_str());
		elem;elem=elem->NextSiblingElement(SpriteLoader::_TILE_TAG.c_str()))
	{
		Tile* tile = TileReader::parse(elem, tilemap);
		if(tile)
			tilemap->addChild(tile);
	}

	for(TiXmlElement* elem=element->FirstChildElement(SpriteLoader::_SPRITE_TAG.c_str());
		elem;elem=elem->NextSiblingElement(SpriteLoader::_SPRITE_TAG.c_str()))
	{
		Sprite* sprite = SpriteLoader::parse(elem);
		if(sprite)
			tilemap->addChild(sprite);
	}

	for(TiXmlElement* elem=element->FirstChildElement(_SHAPE_TAG.c_str());
		elem;elem=elem->NextSiblingElement(_SHAPE_TAG.c_str()))
	{
		ShapeObject* shape = ShapeReader::parse(elem, tilemap);
		if(shape)
			tilemap->addChild(shape);
	}

	for(TiXmlElement* txt=element->FirstChildElement(SpriteLoader::_TEXT_OBJECT_TAG.c_str());
		txt;txt=txt->NextSiblingElement(SpriteLoader::_TEXT_OBJECT_TAG.c_str()))
	{
		TextObject* text = TextReader::parse(txt);
		if(text)
			tilemap->addChild(text);
	}

	for(TiXmlElement* elem=element->FirstChildElement(SpriteLoader::_PARTICLE_TAG.c_str());
		elem;elem=elem->NextSiblingElement(SpriteLoader::_PARTICLE_TAG.c_str()))
	{
		ParticleObject* particle = ParticleReader::parse(elem);
		if(particle)
			tilemap->addChild(particle);
	}

	//retrieves scene manager
	SceneManager& sm = SceneManager::GetInstance();

	//retrieves root object
	RenderObjectContainer* renderRoot = sm.getRenderRoot();

	renderRoot->addChild(tilemap);

	//parse information about scripts
	parseScripts(element, tilemap);

	return tilemap;
}

void TilemapLoader::parseScripts(TiXmlElement* element, Tilemap* tilemap)
{
	char* scriptFile = (char*)element->Attribute(TileReader::_SCRIPT_FILE_TAG.c_str());
	TiXmlElement* node = element->FirstChildElement(TileReader::_SCRIPT_FILE_TAG.c_str()); if(node) scriptFile = (char*)node->GetText();

	if(scriptFile)
	{
#ifdef UNICODE
		TCHAR wstr[512]; memset(wstr, 0, sizeof(wstr));
		::MultiByteToWideChar(CP_UTF8, 0, scriptFile, (int32)strlen(scriptFile), wstr, 512);
		ScriptManager::GetInstance().load(wstr);
#else
		ScriptManager::GetInstance().load(scriptFile);
#endif
	}

	char* onLoad = (char*)element->Attribute(TileReader::_ON_LOAD_TAG.c_str());
	node = element->FirstChildElement(TileReader::_ON_LOAD_TAG.c_str()); if(node) onLoad = (char*)node->GetText();

	if(onLoad)
	{
		//call script function
#ifdef UNICODE
		TCHAR wstr[512]; memset(wstr, 0, sizeof(wstr));
		::MultiByteToWideChar(CP_UTF8, 0, onLoad, (int32)strlen(onLoad), wstr, 512);
		SquirrelFunction<void>((const SQChar*)wstr)(tilemap);
#else
		SquirrelFunction<void>((const SQChar*)onLoad)(tilemap);
#endif
	}
}

Tilemap* TilemapLoader::load(const String& path)
{
	return parse(path);
}
